import { EventEmitter } from "stream"
import { MyServer } from "./MyServer"
import { WebSocket } from "ws"
import { ApiMsgEnum, binaryDecode, binaryEncode, IModel, strdecode, strencode } from "../Common"
import { buffer2ArrayBuffer } from "../Utils"

interface IItem {
    cb: Function
    ctx: unknown
}

export class Connection extends EventEmitter {
    private msgMap: Map<ApiMsgEnum, Array<IItem>> = new Map() // 类似事件订阅的机制，感觉有点像 socket.io 的实现

    constructor(private server: MyServer, private ws: WebSocket) {
        super()
        this.ws.on("close", () => {
            // this.server.connections.delete(this)
            this.emit("close")
        })

        this.ws.on("message", (buffer: Buffer) => {
            try {
                // const str = buffer.toString()
                
                // const ta = new Uint8Array(buffer)
                // const str = strdecode(ta)
                // const msg = JSON.parse(str)
                // const { name, data } = msg

                const json = binaryDecode(buffer2ArrayBuffer(buffer))
                const { name, data } = json

                // api 接口服务
                if (this.server.apiMap.has(name)) {
                    try {
                        const cb = this.server.apiMap.get(name)
                        const res = cb.call(null, this, data)
                        this.sendMsg(name, {
                            success: true,
                            res,
                        })
                    } catch (e) {
                        this.sendMsg(name, {
                            success: false,
                            error: e.message,
                        })
                    }
                } else { // msg 消息服务
                    try {
                        if (this.msgMap.has(name)) {
                            this.msgMap.get(name).forEach(({ cb, ctx }) => {
                                cb.call(ctx, this, data)
                            })
                        }
                    } catch (e) {
                        console.log("处理消息失败:", e)
                    }
                }
            } catch (error) {
                console.log(error)
            }
        })
    }

    // sendMsg(name: string, data) {
    sendMsg<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {
        // const msg = {
        //     name,
        //     data
        // }
        
        // const str = JSON.stringify(msg)
        // const ta = strencode(str)
        // const buffer = Buffer.from(ta)

        const da = binaryEncode(name, data)
        const buffer = Buffer.from(da.buffer)
        this.ws.send(buffer)
        // this.ws.send(JSON.stringify(msg))
    }

    // listenMsg(name: string, cb: Function, ctx: unknown) {
    listenMsg<T extends keyof IModel['msg']>(name: T, cb: (connection: Connection, args: IModel['msg'][T]) => void, ctx: unknown) {
        if (this.msgMap.has(name)) {
            this.msgMap.get(name).push({ cb, ctx })
        } else {
            this.msgMap.set(name, [{ cb, ctx }])
        }
    }

    // unlistenMsg(name: string, cb: Function, ctx: unknown) {
    unlistenMsg<T extends keyof IModel['msg']>(name: T, cb: (connection: Connection, args: IModel['msg'][T]) => void, ctx: unknown) {
        if (this.msgMap.has(name)) {
            const index = this.msgMap.get(name).findIndex((i) => cb === i.cb && i.ctx === ctx);
            index > -1 && this.msgMap.get(name).splice(index, 1);
        }
    }
}
